package com.eliza.base.views.learn.layouts.basic

import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.node.DrawModifierNode
import androidx.compose.ui.node.ModifierNodeElement
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
import com.eliza.base.R
import kotlinx.coroutines.launch

@Preview
@Composable
private fun asd() {

    ModifiersX.Show(navController = rememberNavController())
}

object ModifiersX {
    @Composable
    fun Show(navController: NavController) {
        Column {
            var count by remember {
                mutableIntStateOf(0)
            }
            Button(onClick = { count = (count + 1) % 4 }) {
                Text(text = "ModifiersX $count")
            }
            when (count) {
                0 -> SortX()
                1 -> SizeX()
                2 -> ExampleX()
                3 -> CustomModifiersX.Show(navController)
            }
        }
    }

    @Composable
    private fun SortX() {
        Column {
            Box(
                modifier = Modifier
                    .size(100.dp)
                    .background(Color.Gray)
                    .clip(CircleShape)
            )
            /*
            * Sorts
            * */
            Box(
                modifier = Modifier
                    .requiredSize(100.dp)
                    .background(Color.LightGray)
                    .clip(CircleShape)
                    .border(2.dp, Color.Yellow)

            )
            Box(
                modifier = Modifier
                    .requiredSize(100.dp)
                    .background(Color.Gray)
                    .border(2.dp, Color.Yellow)
                    .clip(CircleShape)

            )
        }
    }

    @Composable
    private fun SizeX() {
        Column {
            Box(
                modifier = Modifier
                    .width(200.dp)
                    .height(50.dp)
                    .background(Color.Yellow)
            ) {
                Text(text = "200 50 width height")
            }
            Box(
                modifier = Modifier
                    .width(200.dp)
                    .height(50.dp)
                    .size(20.dp)
                    .background(Color.Gray)
            ) {
                Text(text = "200 50 => 20width height->size")
            }
            Box(
                modifier = Modifier
                    .size(30.dp)
                    .width(200.dp)
                    .height(50.dp)
                    .background(Color.Yellow)
            ) {
                Text(text = "20 ==> 200 50 size -> width height", fontSize = 6.sp)
            }
            Box(
                modifier = Modifier
                    .sizeIn(
                        30.dp, 30.dp,
                        200.dp, 200.dp,
                    )
                    .background(Color.LightGray)
            ) {
                Text(text = "sizeIn, min w/height - max w/height")
            }

        }
    }

    @Composable
    private fun ExampleX() {
        val imgContentScale: @Composable (
            modifier: Modifier
        ) -> Unit = { modifier ->
            Image(
                painterResource(R.drawable.tou_xiang),
                contentDescription = null,
                modifier
            )
        }
        Column(Modifier.verticalScroll(rememberScrollState())) {
//            fillMaxSize 修饰符会更改约束条件，将最小宽度和高度同时设置为最大值，即宽度为 300dp，高度为 200dp。
//            虽然 size 修饰符想要使用大小为 50dp，但它仍需要遵循传入的最小约束。
//            因此，size 修饰符还会按 200 输出 300 的确切约束范围，实际上会忽略 size 修饰符中提供的值。
            imgContentScale(
                Modifier
                    .fillMaxSize()
                    .size(50.dp)
                    .background(Color.LightGray)
            )
            imgContentScale(
                Modifier
                    .fillMaxSize()
                    .wrapContentSize()
                    .size(50.dp)
                    .background(Color.Yellow)
            )
            imgContentScale(
                Modifier
                    .size(50.dp)
                    .wrapContentSize()
                    .fillMaxSize()
                    .background(Color.Yellow)
            )
            /*
            *   fillMaxSize 修饰符会调整约束，将最小宽度和高度设置为最大值，即宽度为 300dp，高度为 200dp。
                wrapContentSize 修饰符会重置最小约束。因此，虽然 fillMaxSize 会生成固定约束条件，但 wrapContentSize 会将其重置为有边界约束条件。下一个节点现在可以再次占据整个空间，或者小于整个空间。
                size 修饰符将约束条件设置为 50 的最小和最大边界。
                Image 按 50 解析为 50 的大小，然后 size 修饰符会转发该值。
                wrapContentSize 修饰符有一个特殊属性。它会获取它的子项，并将其放在传递给它的可用最小边界的中心。因此，它传递给父级的大小就等于传入它的最小边界。
            * */
            imgContentScale(
                Modifier
                    .clip(CircleShape)
                    .padding(10.dp)
                    .size(100.dp)
                    .background(Color.Blue)
            )

            /*
            *
            * clip 修饰符不会更改约束条件。
                padding 修饰符会降低最大约束。
                size 修饰符将所有约束条件设置为 100dp。
                Image 遵循这些限制，并通过 100dp 报告大小为 100。
                padding 修饰符会针对所有尺寸添加 10dp，因此它会将报告的宽度和高度增加 20dp。
                现在，在绘制阶段，clip 修饰符通过 120dp 对 120 画布起作用。因此，它会创建一个相应大小的圆形遮罩。
                然后，padding 修饰符会在所有尺寸上10dp插入其内容，因此会将画布尺寸降低至 100 100dp。
                系统会在该画布中绘制 Image。图像根据 120dp 的原始圆圈进行裁剪，因此输出为非圆形结果。
            * */
        }
    }

}


object CustomModifiersX {
    @Composable
    fun Show(navController: NavController) {
        Column {
            var count by remember {
                mutableIntStateOf(0)
            }
            Button(onClick = { count = (count + 1) % 4 }) {
                Text(text = "ModifiersX $count")
            }
            when (count) {
                0 -> CustomModifier()
                1 -> MyScreenX()
            }
        }
    }

    @Composable
    private fun CustomModifier() {
        val imgContentScale: @Composable (
            modifier: Modifier
        ) -> Unit = { modifier ->
            Image(
                painterResource(R.drawable.tou_xiang),
                contentDescription = null,
                modifier
            )
        }
        Column {
            imgContentScale(Modifier.myBackground(Color.Gray))
            imgContentScale(Modifier.myBackground(Color.Black))
            imgContentScale(Modifier.fade(true))
            imgContentScale(Modifier.fade(false))
        }
    }

    //    @Composable
//    fun Modifier.clip(shape: Shape) = graphicsLayer(shape = shape, clip = true)
    //封装自定义
    private fun Modifier.myBackground(color: Color): Modifier = then(
        padding(16.dp)
            .clip(RoundedCornerShape(8.dp))
            .background(color)
    )

    @Composable
    private fun Modifier.fade(enable: Boolean): Modifier {
        val alpha by animateFloatAsState(if (enable) 0.5f else 1.0f, label = "alpha")
        return this then Modifier.graphicsLayer { this.alpha = alpha }
    }

    //自定义修饰符是一种提供 CompositionLocal 中的默认值的便捷方法，那么最简单的实现方法是使用可组合修饰符工厂
    @Composable
    private fun Modifier.fadedBackground(): Modifier {
        val color = LocalContentColor.current
        return this then Modifier.background(color.copy(alpha = 0.5f))
    }

    //    CompositionLocal 值在修饰符工厂的调用点进行解析
//    使用可组合项修饰符工厂创建自定义修饰符时，组合局部函数会从创建它们（而不是使用）的组合树中获取值。
//    这可能会导致意外结果。以上面的组合局部修饰符示例为例，该示例使用可组合函数实现的方式略有不同：
    @Composable
    private fun MyScreenX() {
        CompositionLocalProvider(LocalContentColor provides Color.Green) {
            // Background modifier created with green background
            val backgroundModifier = Modifier.myBackground(Color.Gray)

            // LocalContentColor updated to red
            CompositionLocalProvider(LocalContentColor provides Color.Red) {

                // Box will have green background, not red as expected.
                Box(modifier = backgroundModifier)
            }
        }
    }

    @Composable
    private fun NodeX() {
        val imgContentScale: @Composable (
            modifier: Modifier
        ) -> Unit = { modifier ->
            Image(
                painterResource(R.drawable.tou_xiang),
                contentDescription = null,
                modifier
            )
        }
        Column {
            imgContentScale(Modifier.circlex(Color.Gray))
        }
    }

    /*
    * 使用 Modifier.Node 实现自定义修饰符
            使用 Modifier.Node 实现自定义修饰符需要以下三个部分：
            用于保存修饰符的逻辑和状态的 Modifier.Node 实现。
            用于创建和更新修饰符节点实例的 ModifierNodeElement。
            可选的修饰符工厂，如上所述。
    * */
    // Modifier.Node


    /*
    * ModifierNodeElement 是一个不可变类，用于保存用于创建或更新自定义修饰符的数据：
    * ModifierNodeElement 实现需要替换以下方法：

    create：这是用于实例化修饰符节点的函数。首次应用修饰符时，系统会调用该方法以创建节点。
    *   通常，这涉及构建节点并使用传入修饰符工厂的参数对其进行配置。
    update：每当在此节点已存在的同一位置提供此修饰符，但属性发生更改时，系统就会调用此函数。
    *   这由类的 equals 方法确定。之前创建的修饰符节点会作为参数发送到 update 调用。
    * 此时，您应该更新节点的属性，以与更新后的参数相对应。以这种方式重复使用节点的能力是 Modifier.Node 带来的性能提升的关键；因此，您必须更新现有节点，而不是在 update 方法中创建新节点。在我们的圆圈示例中，节点的颜色已更新。
    * */

    // Modifier factory
    fun Modifier.circlex(color: Color) = this then CircleElement(color)

    // ModifierNodeElement
    private data class CircleElement(val color: Color) : ModifierNodeElement<CircleNode>() {
        override fun create() = CircleNode(color)

        override fun update(node: CircleNode) {
            node.color = color
        }
    }

    // Modifier.Node
    private class CircleNode(var color: Color) : DrawModifierNode, Modifier.Node() {
        // 实现动画效果
        private val alpha = Animatable(1f)

        override fun ContentDrawScope.draw() {
            drawCircle(color = color, alpha = alpha.value)
            drawContent()
        }

        override fun onAttach() {
            coroutineScope.launch {
                alpha.animateTo(
                    0f,
                    infiniteRepeatable(tween(1000), RepeatMode.Reverse)
                ) {
                }
            }
        }
    }
}
